package console;

/**
 * This class implements a vector and general manipulation of Vectors
 * 
 * @author nbxx
 *
 */
public class Vector
{
	public double x, y, z;
	public static double temp, tmp;

	/**
	 * Default constructor, using <i>0,0,0</i> as preset co-ordinate.
	 */
	public Vector()
	{
		x = 0;
		y = 0;
		z = 0;
	}
	
	/**
	 * Using input param for setting up co-ordinate.
	 * 
	 * @param x X-Axis ordinate
	 * @param y Y-Axis ordinate
	 * @param z Y-Axis ordinate
	 */
	public Vector(double x, double y, double z)
	{
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	/**
	 * Static Method to calculate addition of two vectors.<br>
	 * Change of param vectors inside the method was inhibited. 
	 * 
	 * @param t First Vector Param
	 * @param v Second Vecor Param
	 * @return Result Vector
	 */
	public static Vector addition(final Vector t, final Vector v)
	{
		return new Vector(t.x+v.x, t.y+v.y, t.z+v.z);
	}
	
	/**
	 * Static Method to calculate subtraction of two vectors.<br>
	 * Change of param vectors inside the method was inhibited. 
	 * 
	 * @param t First Vector Param
	 * @param v Second Vecor Param
	 * @return Result Vector
	 */
	public static Vector subtraction(final Vector t, final Vector v)
	{
		return new Vector(t.x-v.x, t.y-v.y, t.z-v.z);
	}
	
	/**
	 * Static Method to calculate multiplication of vector by a scalar.<br>
	 * Change of params inside the method was inhibited. 
	 * 
	 * @param v Vector Param
	 * @param s Scalar Param
	 * @return Result Vector
	 */
	public static Vector multiplication(final Vector v, final double s)
	{
		return new Vector(v.x*s, v.y*s, v.z*s);
	}
	
	/**
	 * Static Method to calculate division of vector by a scalar.<br>
	 * Change of params inside the method was inhibited. 
	 * 
	 * @param v Vector Param
	 * @param s Scalar Param
	 * @return Result Vector
	 */
	public static Vector division(final Vector v, final double s)
	{
		tmp = 1 / s;
		return new Vector(v.x*tmp, v.y*tmp, v.z*tmp);
	}
	
	/**
	 * Static Method to calculate the cross of two vectors.<br>
	 * Change of param vectors inside the method was inhibited. 
	 * 
	 * @param v First Vector Param
	 * @param t Second Vecor Param
	 * @return Result Vector
	 */
	public static Vector crossing(final Vector v, final Vector t)
	{
		return new Vector(
				v.y*t.z - v.z*t.y,
				v.z*t.x - v.x*t.z,
				v.x*t.y - v.y*t.x);
	}
	
	/**
	 * Compare equality of two vectors in acceptable error. 
	 * 
	 * @param t First param Vector
	 * @param v Second Param Vector
	 * @param e The acceptable error which should be always greater than Epsilon
	 * @return Boolean value to identify if two param vectors are equal in this error
	 */
	public static boolean nearlyEquals( Vector t,Vector v, double e)
	{
		return Math.abs(t.x - v.x) < e && Math.abs(t.y - v.y) < e
				&& Math.abs(t.z - v.z) < e;
	}
	

	/**
	 * Calculate unit vector of handle vector.<br>
	 * Result stored in handle vector
	 * 
	 * @return Unit Vector
	 */
	public Vector unit()
	{
		return Vector.division(this,this.length());
	}
	
	/**
	 * Calculate the cross of handle and param vectors.<br>
	 * Result stored in handle vector.
	 * 
	 * @param v Param Vector
	 * @return Handle Vector 
	 */
	public Vector cross(Vector v)
	{
		tmp = y * v.z - z * v.y;
		temp = z * v.x - x * v.z;
		z = x * v.y - y * v.x;
		x = tmp;
		y = temp;
		return this;
	}
	
	/**
	 * Calculate the crossing dot of handle vector and param vector.
	 * 
	 * @param v param vector
	 * @return The intersection of two vectors
	 */
	public double dot(Vector v)
	{
		return x * v.x + y * v.y + z * v.z;
	}

	/**
	 * Calculate the length of handle vector using unit <i>1</i>
	 * 
	 * @return Length of handle vector
	 */
	public double length()
	{
		return Math.sqrt(x * x + y * y + z * z);
	}

	/**
	 * Check if Handle vector is equal to param one
	 * 
	 * @param v Param Vector
	 * @return boolean value of equality
	 */
	public boolean isEqual(Vector v)
	{
		if (x == v.x && y == v.y && z == v.z)
			return true;
		return false;
	}
	
	/**
	 * Check whether this vector is zero or not
	 * 
	 * @return Is this a zero vector
	 */
	public boolean isZero()
	{
		if (x == 0 && y == 0 && z == 0)
			return true;
		return false;
	}

	/**
	 * Negate the handle vector.<br>
	 * Result stored in handle vector. 
	 * 
	 * @return Handle Vector
	 */
	public Vector negate()
	{
		x = -x;
		y = -y;
		z = -z;
		return this;
	}

	/**
	 * Sign Param vector to handle vector.
	 * 
	 * @param v Param Vector
	 * @return Handle Vector
	 */
	public Vector define(Vector v)
	{
		x = v.x;
		y = v.y;
		z = v.z;
		return this;
	}

	/**
	 * Calculate addition of handle vector and param vector.<br>
	 * Results stored in handle vector.
	 * 
	 * @param v Param Vector
	 * @return Handle Vector
	 */
	public Vector add(Vector v)
	{
		x += v.x;
		y += v.y;
		z += v.z;
		return this;
	}


	/**
	 * Calculate subtraction of handle vector and param vector.<br>
	 * Results stored in handle vector.
	 * 
	 * @param v Param Vector
	 * @return Handle Vector
	 */
	public Vector sub(Vector v)
	{
		x -= v.x;
		y -= v.y;
		z -= v.z;
		return this;
	}


	/**
	 * Calculate multiplication of handle vector and a scalar.<br>
	 * Results stored in handle vector.
	 * 
	 * @param s Param Scalar
	 * @return Handle Vector
	 */
	public Vector mul(double s)
	{
		x *= s;
		y *= s;
		z *= s;
		return this;
	}
	
	/**
	 * Calculate division of handle vector and a scalar.<br>
	 * Results stored in handle vector.
	 * 
	 * @param s Param Scalar
	 * @return Handle Vector
	 */
	public Vector div(double s)
	{
		tmp = 1 / s;
		x *= tmp;
		y *= tmp;
		z *= tmp;
		return this;
	}

	/**
	 * Set the handle vector as unit vector.
	 * 
	 * @return Handle Vector
	 */
	public Vector normalize()
	{
		this.div(this.length());
		return this;
	}
}
